home *** CD-ROM | disk | FTP | other *** search
/ Clickx 63 / Clickx 63.iso / software / multimedia / mirov204 / Miro_Installer.exe / xulrunner / chrome / toolkit.jar / content / global / filepicker.js < prev    next >
Encoding:
Text File  |  2008-04-14  |  24.4 KB  |  834 lines

  1. //@line 44 "/e/xr19rel/WINNT_5.2_Depend/mozilla/toolkit/components/filepicker/content/filepicker.js"
  2.  
  3. const nsIFilePicker       = Components.interfaces.nsIFilePicker;
  4. const nsIProperties       = Components.interfaces.nsIProperties;
  5. const NS_DIRECTORYSERVICE_CONTRACTID = "@mozilla.org/file/directory_service;1";
  6. const NS_IOSERVICE_CONTRACTID = "@mozilla.org/network/io-service;1";
  7. const nsITreeBoxObject = Components.interfaces.nsITreeBoxObject;
  8. const nsIFileView = Components.interfaces.nsIFileView;
  9. const NS_FILEVIEW_CONTRACTID = "@mozilla.org/filepicker/fileview;1";
  10. const nsITreeView = Components.interfaces.nsITreeView;
  11. const nsILocalFile = Components.interfaces.nsILocalFile;
  12. const nsIFile = Components.interfaces.nsIFile;
  13. const NS_LOCAL_FILE_CONTRACTID = "@mozilla.org/file/local;1";
  14. const NS_PROMPTSERVICE_CONTRACTID = "@mozilla.org/embedcomp/prompt-service;1";
  15.  
  16. var sfile = Components.classes[NS_LOCAL_FILE_CONTRACTID].createInstance(nsILocalFile);
  17. var retvals;
  18. var filePickerMode;
  19. var homeDir;
  20. var treeView;
  21. var allowURLs;
  22.  
  23. var textInput;
  24. var okButton;
  25.  
  26. var gFilePickerBundle;
  27.  
  28. // name of new directory entered by the user to be remembered
  29. // for next call of newDir() in case something goes wrong with creation
  30. var gNewDirName = { value: "" };
  31.  
  32. function filepickerLoad() {
  33.   gFilePickerBundle = document.getElementById("bundle_filepicker");
  34.  
  35.   textInput = document.getElementById("textInput");
  36.   okButton = document.documentElement.getButton("accept");
  37.   treeView = Components.classes[NS_FILEVIEW_CONTRACTID].createInstance(nsIFileView);
  38.  
  39.   if (window.arguments) {
  40.     var o = window.arguments[0];
  41.     retvals = o.retvals; /* set this to a global var so we can set return values */
  42.     const title = o.title;
  43.     filePickerMode = o.mode;
  44.     if (o.displayDirectory) {
  45.       const directory = o.displayDirectory.path;
  46.     }
  47.  
  48.     const initialText = o.defaultString;
  49.     const filterTitles = o.filters.titles;
  50.     const filterTypes = o.filters.types;
  51.     const numFilters = filterTitles.length;
  52.  
  53.     document.title = title;
  54.     allowURLs = o.allowURLs;
  55.  
  56.     if (initialText) {
  57.       textInput.value = initialText;
  58.     }
  59.   }
  60.  
  61.   if (filePickerMode != nsIFilePicker.modeOpen && filePickerMode != nsIFilePicker.modeOpenMultiple) {
  62.     var newDirButton = document.getElementById("newDirButton");
  63.     newDirButton.removeAttribute("hidden");
  64.   }
  65.  
  66.   if (filePickerMode == nsIFilePicker.modeGetFolder) {
  67.     var textInputLabel = document.getElementById("textInputLabel");
  68.     textInputLabel.value = gFilePickerBundle.getString("dirTextInputLabel");
  69.     textInputLabel.accessKey = gFilePickerBundle.getString("dirTextInputAccesskey");
  70.   }
  71.   
  72.   if ((filePickerMode == nsIFilePicker.modeOpen) ||
  73.       (filePickerMode == nsIFilePicker.modeOpenMultiple) ||
  74.       (filePickerMode == nsIFilePicker.modeSave)) {
  75.  
  76.     /* build filter popup */
  77.     var filterPopup = document.createElement("menupopup");
  78.  
  79.     for (var i = 0; i < numFilters; i++) {
  80.       var menuItem = document.createElement("menuitem");
  81.       if (filterTypes[i] == "..apps")
  82.         menuItem.setAttribute("label", filterTitles[i]);
  83.       else
  84.         menuItem.setAttribute("label", filterTitles[i] + " (" + filterTypes[i] + ")");
  85.       menuItem.setAttribute("filters", filterTypes[i]);
  86.       filterPopup.appendChild(menuItem);
  87.     }
  88.  
  89.     var filterMenuList = document.getElementById("filterMenuList");
  90.     filterMenuList.appendChild(filterPopup);
  91.     if (numFilters > 0)
  92.       filterMenuList.selectedIndex = 0;
  93.     var filterBox = document.getElementById("filterBox");
  94.     filterBox.removeAttribute("hidden");
  95.  
  96.     filterMenuList.selectedIndex = o.filterIndex;
  97.  
  98.     treeView.setFilter(filterTypes[o.filterIndex]);
  99.  
  100.   } else if (filePickerMode == nsIFilePicker.modeGetFolder) {
  101.     treeView.showOnlyDirectories = true;
  102.   }
  103.  
  104.   // The dialog defaults to an "open" icon, change it to "save" if applicable
  105.   if (filePickerMode == nsIFilePicker.modeSave)
  106.     okButton.setAttribute("icon", "save");
  107.  
  108.   // start out with a filename sort
  109.   handleColumnClick("FilenameColumn");
  110.  
  111.   try {
  112.     setOKAction();
  113.   } catch (exception) {
  114.     // keep it set to "OK"
  115.   }
  116.  
  117.   // setup the dialogOverlay.xul button handlers
  118.   retvals.buttonStatus = nsIFilePicker.returnCancel;
  119.  
  120.   var tree = document.getElementById("directoryTree");
  121.   if (filePickerMode == nsIFilePicker.modeOpenMultiple)
  122.     tree.removeAttribute("seltype");
  123.  
  124.   tree.treeBoxObject.view = treeView;
  125.  
  126.   // Start out with the ok button disabled since nothing will be
  127.   // selected and nothing will be in the text field.
  128.   okButton.disabled = filePickerMode != nsIFilePicker.modeGetFolder;
  129.  
  130.   // This allows the window to show onscreen before we begin
  131.   // loading the file list
  132.  
  133.   setTimeout(setInitialDirectory, 0, directory);
  134. }
  135.  
  136. function setInitialDirectory(directory)
  137. {
  138.   // Start in the user's home directory
  139.   var dirService = Components.classes[NS_DIRECTORYSERVICE_CONTRACTID]
  140.                              .getService(nsIProperties);
  141.   homeDir = dirService.get("Home", Components.interfaces.nsIFile);
  142.  
  143.   if (directory) {
  144.     sfile.initWithPath(directory);
  145.     if (!sfile.exists() || !sfile.isDirectory())
  146.       directory = false;
  147.   }
  148.   if (!directory) {
  149.     sfile.initWithPath(homeDir.path);
  150.   }
  151.  
  152.   gotoDirectory(sfile);
  153. }
  154.  
  155. function onFilterChanged(target)
  156. {
  157.   // Do this on a timeout callback so the filter list can roll up
  158.   // and we don't keep the mouse grabbed while we are refiltering.
  159.  
  160.   setTimeout(changeFilter, 0, target.getAttribute("filters"));
  161. }
  162.  
  163. function changeFilter(filterTypes)
  164. {
  165.   window.setCursor("wait");
  166.   treeView.setFilter(filterTypes);
  167.   window.setCursor("auto");
  168. }
  169.  
  170. function showErrorDialog(titleStrName, messageStrName, file)
  171. {
  172.   var errorTitle =
  173.     gFilePickerBundle.getFormattedString(titleStrName, [file.path]);
  174.   var errorMessage =
  175.     gFilePickerBundle.getFormattedString(messageStrName, [file.path]);
  176.   var promptService =
  177.     Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService);
  178.  
  179.   promptService.alert(window, errorTitle, errorMessage);
  180. }
  181.  
  182. function openOnOK()
  183. {
  184.   var dir = treeView.selectedFiles.queryElementAt(0, nsIFile);
  185.   if (dir)
  186.     gotoDirectory(dir);
  187.  
  188.   return false;
  189. }
  190.  
  191. function selectOnOK()
  192. {
  193.   var errorTitle, errorMessage, promptService;
  194.   var ret = nsIFilePicker.returnOK;
  195.  
  196.   var isDir = false;
  197.   var isFile = false;
  198.  
  199.   retvals.filterIndex = document.getElementById("filterMenuList").selectedIndex;
  200.   retvals.fileURL = null;
  201.  
  202.   if (allowURLs) {
  203.     try {
  204.       var ios = Components.classes[NS_IOSERVICE_CONTRACTID].getService(Components.interfaces.nsIIOService);
  205.       retvals.fileURL = ios.newURI(textInput.value, null, null);
  206.       var fileList = [];
  207.       if (retvals.fileURL instanceof Components.interfaces.nsIFileURL)
  208.         fileList.push(retvals.fileURL.file);
  209.       gFilesEnumerator.mFiles = fileList;
  210.       retvals.files = gFilesEnumerator;
  211.       retvals.buttonStatus = ret;
  212.  
  213.       return true;
  214.     } catch (e) {
  215.     }
  216.   }
  217.  
  218.   var fileList = processPath(textInput.value);
  219.   if (!fileList) {
  220.     // generic error message, should probably never happen
  221.     showErrorDialog("errorPathProblemTitle",
  222.                     "errorPathProblemMessage",
  223.                     textInput.value);
  224.     return false;
  225.   }
  226.  
  227.   var curFileIndex;
  228.   for (curFileIndex = 0; curFileIndex < fileList.length &&
  229.          ret != nsIFilePicker.returnCancel; ++curFileIndex) {
  230.     var file = fileList[curFileIndex].QueryInterface(nsIFile);
  231.  
  232.     // try to normalize - if this fails we will ignore the error
  233.     // because we will notice the
  234.     // error later and show a fitting error alert.
  235.     try{
  236.       file.normalize();
  237.     } catch(e) {
  238.       //promptService.alert(window, "Problem", "normalize failed, continuing");
  239.     }
  240.  
  241.     var fileExists = file.exists();
  242.  
  243.     if (!fileExists && (filePickerMode == nsIFilePicker.modeOpen ||
  244.                         filePickerMode == nsIFilePicker.modeOpenMultiple)) {
  245.       showErrorDialog("errorOpenFileDoesntExistTitle",
  246.                       "errorOpenFileDoesntExistMessage",
  247.                       file);
  248.       return false;
  249.     }
  250.  
  251.     if (!fileExists && filePickerMode == nsIFilePicker.modeGetFolder) {
  252.       showErrorDialog("errorDirDoesntExistTitle",
  253.                       "errorDirDoesntExistMessage",
  254.                       file);
  255.       return false;
  256.     }
  257.  
  258.     if (fileExists) {
  259.       isDir = file.isDirectory();
  260.       isFile = file.isFile();
  261.     }
  262.  
  263.     switch(filePickerMode) {
  264.     case nsIFilePicker.modeOpen:
  265.     case nsIFilePicker.modeOpenMultiple:
  266.       if (isFile) {
  267.         if (file.isReadable()) {
  268.           retvals.directory = file.parent.path;
  269.         } else {
  270.           showErrorDialog("errorOpeningFileTitle",
  271.                           "openWithoutPermissionMessage_file",
  272.                           file);
  273.           ret = nsIFilePicker.returnCancel;
  274.         }
  275.       } else if (isDir) {
  276.         if (!sfile.equals(file)) {
  277.           gotoDirectory(file);
  278.         }
  279.         textInput.value = "";
  280.         doEnabling();
  281.         ret = nsIFilePicker.returnCancel;
  282.       }
  283.       break;
  284.     case nsIFilePicker.modeSave:
  285.       if (isFile) { // can only be true if file.exists()
  286.         if (!file.isWritable()) {
  287.           showErrorDialog("errorSavingFileTitle",
  288.                           "saveWithoutPermissionMessage_file",
  289.                           file);
  290.           ret = nsIFilePicker.returnCancel;
  291.         } else {
  292.           // we need to pop up a dialog asking if you want to save
  293.           var confirmTitle = gFilePickerBundle.getString("confirmTitle");
  294.           var message =
  295.             gFilePickerBundle.getFormattedString("confirmFileReplacing",
  296.                                                  [file.path]);
  297.           
  298.           promptService = Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService);
  299.           var rv = promptService.confirm(window, confirmTitle, message);
  300.           if (rv) {
  301.             ret = nsIFilePicker.returnReplace;
  302.             retvals.directory = file.parent.path;
  303.           } else {
  304.             ret = nsIFilePicker.returnCancel;
  305.           }
  306.         }
  307.       } else if (isDir) {
  308.         if (!sfile.equals(file)) {
  309.           gotoDirectory(file);
  310.         }
  311.         textInput.value = "";
  312.         doEnabling();
  313.         ret = nsIFilePicker.returnCancel;
  314.       } else {
  315.         var parent = file.parent;
  316.         if (parent.exists() && parent.isDirectory() && parent.isWritable()) {
  317.           retvals.directory = parent.path;
  318.         } else {
  319.           var oldParent = parent;
  320.           while (!parent.exists()) {
  321.             oldParent = parent;
  322.             parent = parent.parent;
  323.           }
  324.           errorTitle =
  325.             gFilePickerBundle.getFormattedString("errorSavingFileTitle",
  326.                                                  [file.path]);
  327.           if (parent.isFile()) {
  328.             errorMessage =
  329.               gFilePickerBundle.getFormattedString("saveParentIsFileMessage",
  330.                                                    [parent.path, file.path]);
  331.           } else {
  332.             errorMessage =
  333.               gFilePickerBundle.getFormattedString("saveParentDoesntExistMessage",
  334.                                                    [oldParent.path, file.path]);
  335.           }
  336.           if (!parent.isWritable()) {
  337.             errorMessage =
  338.               gFilePickerBundle.getFormattedString("saveWithoutPermissionMessage_dir", [parent.path]);
  339.           }
  340.           promptService = Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService);
  341.           promptService.alert(window, errorTitle, errorMessage);
  342.           ret = nsIFilePicker.returnCancel;
  343.         }
  344.       }
  345.       break;
  346.     case nsIFilePicker.modeGetFolder:
  347.       if (isDir) {
  348.         retvals.directory = file.parent.path;
  349.       } else { // if nothing selected, the current directory will be fine
  350.         retvals.directory = sfile.path;
  351.       }
  352.       break;
  353.     }
  354.   }
  355.  
  356.   gFilesEnumerator.mFiles = fileList;
  357.  
  358.   retvals.files = gFilesEnumerator;
  359.   retvals.buttonStatus = ret;
  360.   
  361.   return (ret != nsIFilePicker.returnCancel);
  362. }
  363.  
  364. var gFilesEnumerator = {
  365.   mFiles: null,
  366.   mIndex: 0,
  367.  
  368.   hasMoreElements: function()
  369.   {
  370.     return (this.mIndex < this.mFiles.length);
  371.   },
  372.   getNext: function()
  373.   {
  374.     if (this.mIndex >= this.mFiles.length)
  375.       throw Components.results.NS_ERROR_FAILURE;
  376.     return this.mFiles[this.mIndex++];
  377.   }
  378. };
  379.  
  380. function onCancel()
  381. {
  382.   // Close the window.
  383.   retvals.buttonStatus = nsIFilePicker.returnCancel;
  384.   retvals.file = null;
  385.   retvals.files = null;
  386.   return true;
  387. }
  388.  
  389. function onDblClick(e) {
  390.   // we only care about button 0 (left click) events
  391.   if (e.button != 0) return;
  392.  
  393.   var t = e.originalTarget;
  394.   if (t.localName != "treechildren")
  395.     return;
  396.  
  397.   openSelectedFile();
  398. }
  399.  
  400. function openSelectedFile() {
  401.   var fileList = treeView.selectedFiles;
  402.   if (fileList.length == 0)
  403.     return;
  404.  
  405.   var file = fileList.queryElementAt(0, nsIFile);
  406.   if (file.isDirectory())
  407.     gotoDirectory(file);
  408.   else if (file.isFile())
  409.     document.documentElement.acceptDialog();
  410. }
  411.  
  412. function onClick(e) {
  413.   var t = e.originalTarget;
  414.   if (t.localName == "treecol")
  415.     handleColumnClick(t.id);
  416. }
  417.  
  418. function convertColumnIDtoSortType(columnID) {
  419.   var sortKey;
  420.   
  421.   switch (columnID) {
  422.   case "FilenameColumn":
  423.     sortKey = nsIFileView.sortName;
  424.     break;
  425.   case "FileSizeColumn":
  426.     sortKey = nsIFileView.sortSize;
  427.     break;
  428.   case "LastModifiedColumn":
  429.     sortKey = nsIFileView.sortDate;
  430.     break;
  431.   default:
  432.     dump("unsupported sort column: " + columnID + "\n");
  433.     sortKey = 0;
  434.     break;
  435.   }
  436.   
  437.   return sortKey;
  438. }
  439.  
  440. function handleColumnClick(columnID) {
  441.   var sortType = convertColumnIDtoSortType(columnID);
  442.   var sortOrder = (treeView.sortType == sortType) ? !treeView.reverseSort : false;
  443.   treeView.sort(sortType, sortOrder);
  444.   
  445.   // set the sort indicator on the column we are sorted by
  446.   var sortedColumn = document.getElementById(columnID);
  447.   if (treeView.reverseSort) {
  448.     sortedColumn.setAttribute("sortDirection", "descending");
  449.   } else {
  450.     sortedColumn.setAttribute("sortDirection", "ascending");
  451.   }
  452.   
  453.   // remove the sort indicator from the rest of the columns
  454.   var currCol = sortedColumn.parentNode.firstChild;
  455.   while (currCol) {
  456.     if (currCol != sortedColumn && currCol.localName == "treecol")
  457.       currCol.removeAttribute("sortDirection");
  458.     currCol = currCol.nextSibling;
  459.   }
  460. }
  461.  
  462. function onKeypress(e) {
  463.   if (e.keyCode == 8) /* backspace */
  464.     goUp();
  465.  
  466.   /* enter is handled by the ondialogaccept handler */
  467. }
  468.  
  469. function doEnabling() {
  470.   if (filePickerMode != nsIFilePicker.modeGetFolder)
  471.   // Maybe add check if textInput.value would resolve to an existing
  472.   // file or directory in .modeOpen. Too costly I think.
  473.     okButton.disabled = (textInput.value == "")
  474. }
  475.  
  476. function onTreeFocus(event) {
  477.   // Reset the button label and enabled/disabled state.
  478.   onFileSelected(treeView.selectedFiles);
  479. }
  480.  
  481. function setOKAction(file) {
  482.   var buttonLabel;
  483.   var buttonIcon = "open"; // used in all but one case
  484.  
  485.   if (file && file.isDirectory()) {
  486.     document.documentElement.setAttribute("ondialogaccept", "return openOnOK();");
  487.     buttonLabel = gFilePickerBundle.getString("openButtonLabel");
  488.   }
  489.   else {
  490.     document.documentElement.setAttribute("ondialogaccept", "return selectOnOK();");
  491.     switch(filePickerMode) {
  492.     case nsIFilePicker.modeGetFolder:
  493.       buttonLabel = gFilePickerBundle.getString("selectFolderButtonLabel");
  494.       break;
  495.     case nsIFilePicker.modeOpen:
  496.     case nsIFilePicker.modeOpenMultiple:
  497.       buttonLabel = gFilePickerBundle.getString("openButtonLabel");
  498.       break;
  499.     case nsIFilePicker.modeSave:
  500.       buttonLabel = gFilePickerBundle.getString("saveButtonLabel");
  501.       buttonIcon = "save";
  502.       break;
  503.     }
  504.   }
  505.   okButton.setAttribute("label", buttonLabel);
  506.   okButton.setAttribute("icon", buttonIcon);
  507. }
  508.  
  509. function onSelect(event) {
  510.   onFileSelected(treeView.selectedFiles);
  511. }
  512.  
  513. function onFileSelected(/* nsIArray */ selectedFileList) {
  514.   var validFileSelected = false;
  515.   var invalidSelection = false;
  516.   var file;
  517.   var fileCount = selectedFileList.length;
  518.  
  519.   for (var index = 0; index < fileCount; ++index) {
  520.     file = selectedFileList.queryElementAt(index, nsIFile);
  521.     if (file) {
  522.       var path = file.leafName;
  523.  
  524.       if (path) {
  525.         var isDir = file.isDirectory();
  526.         if ((filePickerMode == nsIFilePicker.modeGetFolder) || !isDir) {
  527.           if (!validFileSelected)
  528.             textInput.value = "";
  529.           addToTextFieldValue(path);
  530.         }
  531.  
  532.         if (isDir && fileCount > 1) {
  533.           // The user has selected multiple items, and one of them is
  534.           // a directory.  This is not a valid state, so we'll disable
  535.           // the ok button.
  536.           invalidSelection = true;
  537.         }
  538.  
  539.         validFileSelected = true;
  540.       }
  541.     }
  542.   }
  543.  
  544.   if (validFileSelected) {
  545.     setOKAction(file);
  546.     okButton.disabled = invalidSelection;
  547.   } else if (filePickerMode != nsIFilePicker.modeGetFolder)
  548.     okButton.disabled = (textInput.value == "");
  549. }
  550.  
  551. function addToTextFieldValue(path)
  552. {
  553.   var newValue = "";
  554.  
  555.   if (textInput.value == "")
  556.     newValue = path.replace(/\"/g, "\\\"");
  557.   else {
  558.     // Quote the existing text if needed,
  559.     // then append the new filename (quoted and escaped)
  560.     if (textInput.value[0] != '"')
  561.       newValue = '"' + textInput.value.replace(/\"/g, "\\\"") + '"';
  562.     else
  563.       newValue = textInput.value;
  564.  
  565.     newValue = newValue + ' "' + path.replace(/\"/g, "\\\"") + '"';
  566.   }
  567.  
  568.   textInput.value = newValue;
  569. }
  570.  
  571. function onTextFieldFocus() {
  572.   setOKAction(null);
  573.   doEnabling();
  574. }
  575.  
  576. function onDirectoryChanged(target)
  577. {
  578.   var path = target.getAttribute("label");
  579.  
  580.   var file = Components.classes[NS_LOCAL_FILE_CONTRACTID].createInstance(nsILocalFile);
  581.   file.initWithPath(path);
  582.  
  583.   if (!sfile.equals(file)) {
  584.     // Do this on a timeout callback so the directory list can roll up
  585.     // and we don't keep the mouse grabbed while we are loading.
  586.  
  587.     setTimeout(gotoDirectory, 0, file);
  588.   }
  589. }
  590.  
  591. function populateAncestorList(directory) {
  592.   var menu = document.getElementById("lookInMenu");
  593.  
  594.   while (menu.hasChildNodes()) {
  595.     menu.removeChild(menu.firstChild);
  596.   }
  597.   
  598.   var menuItem = document.createElement("menuitem");
  599.   menuItem.setAttribute("label", directory.path);
  600.   menuItem.setAttribute("crop", "start");
  601.   menu.appendChild(menuItem);
  602.  
  603.   // .parent is _sometimes_ null, see bug 121489.  Do a dance around that.
  604.   var parent = directory.parent;
  605.   while (parent && !parent.equals(directory)) {
  606.     menuItem = document.createElement("menuitem");
  607.     menuItem.setAttribute("label", parent.path);
  608.     menuItem.setAttribute("crop", "start");
  609.     menu.appendChild(menuItem);
  610.     directory = parent;
  611.     parent = directory.parent;
  612.   }
  613.   
  614.   var menuList = document.getElementById("lookInMenuList");
  615.   menuList.selectedIndex = 0;
  616. }
  617.  
  618. function goUp() {
  619.   try {
  620.     var parent = sfile.parent;
  621.   } catch(ex) { dump("can't get parent directory\n"); }
  622.  
  623.   if (parent) {
  624.     gotoDirectory(parent);
  625.   }
  626. }
  627.  
  628. function goHome() {
  629.   gotoDirectory(homeDir);
  630. }
  631.  
  632. function newDir() {
  633.   var file;
  634.   var promptService =
  635.     Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService);
  636.   var dialogTitle =
  637.     gFilePickerBundle.getString("promptNewDirTitle");
  638.   var dialogMsg =
  639.     gFilePickerBundle.getString("promptNewDirMessage");
  640.   var ret = promptService.prompt(window, dialogTitle, dialogMsg, gNewDirName, null, {value:0});
  641.  
  642.   if (ret) {
  643.     file = processPath(gNewDirName.value);
  644.     if (!file) {
  645.       showErrorDialog("errorCreateNewDirTitle",
  646.                       "errorCreateNewDirMessage",
  647.                       file);
  648.       return false;
  649.     }
  650.     
  651.     file = file[0].QueryInterface(nsIFile);
  652.     if (file.exists()) {
  653.       showErrorDialog("errorNewDirDoesExistTitle",
  654.                       "errorNewDirDoesExistMessage",
  655.                       file);
  656.       return false;
  657.     }
  658.  
  659.     var parent = file.parent;
  660.     if (!(parent.exists() && parent.isDirectory() && parent.isWritable())) {
  661.       var oldParent = parent;
  662.       while (!parent.exists()) {
  663.         oldParent = parent;
  664.         parent = parent.parent;
  665.       }
  666.       if (parent.isFile()) {
  667.         showErrorDialog("errorCreateNewDirTitle",
  668.                         "errorCreateNewDirIsFileMessage",
  669.                         parent);
  670.         return false;
  671.       }
  672.       if (!parent.isWritable()) {
  673.         showErrorDialog("errorCreateNewDirTitle",
  674.                         "errorCreateNewDirPermissionMessage",
  675.                         parent);
  676.         return false;
  677.       }
  678.     }
  679.  
  680.     try {
  681.       file.create(nsIFile.DIRECTORY_TYPE, 0755); 
  682.     } catch (e) {
  683.       showErrorDialog("errorCreateNewDirTitle",
  684.                       "errorCreateNewDirMessage",
  685.                       file);
  686.       return false;
  687.     }
  688.     file.normalize(); // ... in case ".." was used in the path
  689.     gotoDirectory(file);
  690.     // we remember and reshow a dirname if something goes wrong
  691.     // so that errors can be corrected more easily. If all went well,
  692.     // reset the default value to blank
  693.     gNewDirName = { value: "" }; 
  694.   }
  695.   return true;
  696. }
  697.  
  698. function gotoDirectory(directory) {
  699.   window.setCursor("wait");
  700.   try {
  701.     populateAncestorList(directory);
  702.     treeView.setDirectory(directory);
  703.     document.getElementById("errorShower").selectedIndex = 0;
  704.   } catch(ex) {
  705.     document.getElementById("errorShower").selectedIndex = 1;
  706.   }
  707.  
  708.   window.setCursor("auto");
  709.  
  710.   if (filePickerMode == nsIFilePicker.modeGetFolder) {
  711.     textInput.value = "";
  712.   }
  713.   textInput.focus();
  714.   textInput.setAttribute("autocompletesearchparam", directory.path);
  715.   sfile = directory;
  716. }
  717.  
  718. function toggleShowHidden(event) {
  719.   treeView.showHiddenFiles = !treeView.showHiddenFiles;
  720. }
  721.  
  722. // from the current directory and whatever was entered
  723. // in the entry field, try to make a new path. This
  724. // uses "/" as the directory separator, "~" as a shortcut
  725. // for the home directory (but only when seen at the start
  726. // of a path), and ".." to denote the parent directory.
  727. // returns an array of the files listed,
  728. // or false if an error occurred.
  729. function processPath(path)
  730. {
  731.   var fileArray = new Array();
  732.   var strLength = path.length;
  733.  
  734.   if (path[0] == '"' && filePickerMode == nsIFilePicker.modeOpenMultiple &&
  735.       strLength > 1) {
  736.     // we have a quoted list of filenames, separated by spaces.
  737.     // iterate the list and process each file.
  738.  
  739.     var curFileStart = 1;
  740.  
  741.     while (1) {
  742.       var nextQuote;
  743.  
  744.       // Look for an unescaped quote
  745.       var quoteSearchStart = curFileStart + 1;
  746.       do {
  747.         nextQuote = path.indexOf('"', quoteSearchStart);
  748.         quoteSearchStart = nextQuote + 1;
  749.       } while (nextQuote != -1 && path[nextQuote - 1] == '\\');
  750.       
  751.       if (nextQuote == -1) {
  752.         // we have a filename with no trailing quote.
  753.         // just assume that the filename ends at the end of the string.
  754.  
  755.         if (!processPathEntry(path.substring(curFileStart), fileArray))
  756.           return false;
  757.         break;
  758.       }
  759.  
  760.       if (!processPathEntry(path.substring(curFileStart, nextQuote), fileArray))
  761.         return false;
  762.  
  763.       curFileStart = path.indexOf('"', nextQuote + 1);
  764.       if (curFileStart == -1) {
  765.         // no more quotes, but if we're not at the end of the string,
  766.         // go ahead and process the remaining text.
  767.  
  768.         if (nextQuote < strLength - 1)
  769.           if (!processPathEntry(path.substring(nextQuote + 1), fileArray))
  770.             return false;
  771.         break;
  772.       }
  773.       ++curFileStart;
  774.     }
  775.   } else {
  776.     // If we didn't start with a quote, assume we just have a single file.
  777.     if (!processPathEntry(path, fileArray))
  778.       return false;
  779.   }
  780.  
  781.   return fileArray;
  782. }
  783.  
  784. function processPathEntry(path, fileArray)
  785. {
  786.   var filePath;
  787.   var file;
  788.  
  789.   try {
  790.     file = sfile.clone().QueryInterface(nsILocalFile);
  791.   } catch(e) {
  792.     dump("Couldn't clone\n"+e);
  793.     return false;
  794.   }
  795.  
  796.   var tilde_file = file.clone();
  797.   tilde_file.append("~");
  798.   if (path[0] == '~' &&                        // Expand ~ to $HOME, except:
  799.       !(path == "~" && tilde_file.exists()) && // If ~ was entered and such a file exists, don't expand
  800.       (path.length == 1 || path[1] == "/"))    // We don't want to expand ~file to ${HOME}file
  801.     filePath = homeDir.path + path.substring(1);
  802.   else
  803.     filePath = path;
  804.  
  805.   // Unescape quotes
  806.   filePath = filePath.replace(/\\\"/g, "\"");
  807.   
  808.   if (filePath[0] == '/')   /* an absolute path was entered */
  809.     file.initWithPath(filePath);
  810.   else if ((filePath.indexOf("/../") > 0) ||
  811.            (filePath.substr(-3) == "/..") ||
  812.            (filePath.substr(0,3) == "../") ||
  813.            (filePath == "..")) {
  814.     /* appendRelativePath doesn't allow .. */
  815.     try{
  816.       file.initWithPath(file.path + "/" + filePath);
  817.     } catch (e) {
  818.       dump("Couldn't init path\n"+e);
  819.       return false;
  820.     }
  821.   }
  822.   else {
  823.     try {
  824.       file.appendRelativePath(filePath);
  825.     } catch (e) {
  826.       dump("Couldn't append path\n"+e);
  827.       return false;
  828.     }
  829.   }
  830.  
  831.   fileArray[fileArray.length] = file;
  832.   return true;
  833. }
  834.